package gsolution;

import gio.FichierEntree;
import gproblem.GJobData;
import gproblem.GSupplyLinkProblem;
import gproblem.GSupplyLinkTransporter;

import java.util.*;

/**
 * A Solution for the optimisation problem
 * 
 * @author Olivier Grunder
 * @version 0.01
 * @date 13 avril 2011
 *
 */
public class GSupplyLinkSolution {

	GSupplyLinkProblem supplyLinkProblem;

	/*
	 * Structure of a feasible schedule ;
	 */
	private GJobVariable[] processingSchedule;

	/*
	 * Number of batches
	 */
	int nbrBatch;

	/*
	 * Sum of production Completion Dates ; Used for lagrangian relaxation
	 * approach ;
	 */
	private double makespanForProduction = 0;

	/*
	 * Sum of transportation Completion Dates ; Used for lagrangian relaxation
	 * approach ;
	 */
	private double makespanForTransportation = 0;

	/*
	 * solValueOfTransportationProblem Used for lagrangian relaxation approach ;
	 */
	private double solValueOfTransportationProblem = 0;

	private double evaluation;
	private double evaluationTransporter;
	private double evaluationCustomer;

	/*
	 * Array of the first transporter departure, indice is a transporter
	 */
	private double dateTransporterDeparture[];
	private double dateProductionDeparture;

	public static final double MOINS_INFINI = -1000000.0;

	/*
	 * 
	 */
	public GSupplyLinkSolution() {
		supplyLinkProblem = null;
	}

	public GSupplyLinkSolution(GSupplyLinkProblem pb, String string) {
		setSupplyLinkProblem(pb) ;
		open (string) ;
	}

	/**
	 * @param slpb
	 * @param processingSchedule
	 * @param nbrBatch
	 * @param makespanForProduction
	 * @param makespanForTransportation
	 * @param solValueOfTransportationProblem
	 * @param evaluationManufacturer
	 * @param evaluationTransporter
	 * @param evaluationCustomer
	 * @param dateTransporterDeparture
	 * @param dateProductionDeparture
	 */
	public GSupplyLinkSolution(GSupplyLinkProblem supplyLinkProblem,
			GJobVariable[] processingSchedule, int nbrBatch,
			double makespanForProduction, double makespanForTransportation,
			double solValueOfTransportationProblem,
			double evaluationManufacturer, double evaluationTransporter,
			double evaluationCustomer, double[] dateTransporterDeparture,
			double dateProductionDeparture) {
		this.supplyLinkProblem = supplyLinkProblem;
		this.processingSchedule = processingSchedule;
		this.nbrBatch = nbrBatch;
		this.makespanForProduction = makespanForProduction;
		this.makespanForTransportation = makespanForTransportation;
		this.solValueOfTransportationProblem = solValueOfTransportationProblem;
		this.evaluation = evaluationManufacturer;
		this.evaluationTransporter = evaluationTransporter;
		this.evaluationCustomer = evaluationCustomer;
		this.dateTransporterDeparture = dateTransporterDeparture;
		this.dateProductionDeparture = dateProductionDeparture;
	}

	/**
	 * @return the slpb
	 */
	public GSupplyLinkProblem getSupplyLinkProblem() {
		return supplyLinkProblem;
	}

	/**
	 * @param slpb
	 *            the slpb to set
	 */
	public void setSupplyLinkProblem(GSupplyLinkProblem slpb) {
		this.supplyLinkProblem = slpb;
		if (this.supplyLinkProblem.getN()>0) {
			processingSchedule = new GJobVariable[this.supplyLinkProblem.getN()] ;
			for (int i=0;i<this.supplyLinkProblem.getN();++i) 
				processingSchedule[i] = new GJobVariable();
		}
	}

	/**
	 * @return the processingSchedule
	 */
	public GJobVariable[] getProcessingSchedule() {
		return processingSchedule;
	}

	/**
	 * @param processingSchedule
	 *            the processingSchedule to set
	 */
	public void setProcessingSchedule(GJobVariable[] processingSchedule) {
		this.processingSchedule = processingSchedule;
	}

	/**
	 * @return the nbrBatch
	 */
	public int getNbrBatch() {
		return nbrBatch;
	}

	/**
	 * @param nbrBatch
	 *            the nbrBatch to set
	 */
	public void setNbrBatch(int nbrBatch) {
		this.nbrBatch = nbrBatch;
	}

	/**
	 * @return the makespanForProduction
	 */
	public double getMakespanForProduction() {
		return makespanForProduction;
	}

	/**
	 * @param makespanForProduction
	 *            the makespanForProduction to set
	 */
	public void setMakespanForProduction(double makespanForProduction) {
		this.makespanForProduction = makespanForProduction;
	}

	/**
	 * @return the makespanForTransportation
	 */
	public double getMakespanForTransportation() {
		return makespanForTransportation;
	}

	/**
	 * @param makespanForTransportation
	 *            the makespanForTransportation to set
	 */
	public void setMakespanForTransportation(double makespanForTransportation) {
		this.makespanForTransportation = makespanForTransportation;
	}

	/**
	 * @return the solValueOfTransportationProblem
	 */
	public double getSolValueOfTransportationProblem() {
		return solValueOfTransportationProblem;
	}

	/**
	 * @param solValueOfTransportationProblem
	 *            the solValueOfTransportationProblem to set
	 */
	public void setSolValueOfTransportationProblem(
			double solValueOfTransportationProblem) {
		this.solValueOfTransportationProblem = solValueOfTransportationProblem;
	}

	/**
	 * @return the evaluationManufacturer
	 */
	public double getEvaluation() {
		return evaluation;
	}

	/**
	 * @param evaluationManufacturer
	 *            the evaluationManufacturer to set
	 */
	public void setEvaluation(double evaluation) {
		this.evaluation = evaluation;
	}

	/**
	 * @return the evaluationTransporter
	 */
	public double getEvaluationTransporter() {
		return evaluationTransporter;
	}

	/**
	 * @param evaluationTransporter
	 *            the evaluationTransporter to set
	 */
	public void setEvaluationTransporter(double evaluationTransporter) {
		this.evaluationTransporter = evaluationTransporter;
	}

	/**
	 * @return the evaluationCustomer
	 */
	public double getEvaluationCustomer() {
		return evaluationCustomer;
	}

	/**
	 * @param evaluationCustomer
	 *            the evaluationCustomer to set
	 */
	public void setEvaluationCustomer(double evaluationCustomer) {
		this.evaluationCustomer = evaluationCustomer;
	}

	/**
	 * @return the dateTransporterDeparture
	 */
	public double[] getDateTransporterDeparture() {
		return dateTransporterDeparture;
	}

	/**
	 * @param dateTransporterDeparture
	 *            the dateTransporterDeparture to set
	 */
	public void setDateTransporterDeparture(double[] dateTransporterDeparture) {
		this.dateTransporterDeparture = dateTransporterDeparture;
	}

	/**
	 * @return the dateProductionDeparture
	 */
	public double getDateProductionDeparture() {
		return dateProductionDeparture;
	}

	/**
	 * @param dateProductionDeparture
	 *            the dateProductionDeparture to set
	 */
	public void setDateProductionDeparture(double dateProductionDeparture) {
		this.dateProductionDeparture = dateProductionDeparture;
	}

	/**
	 * @return the moinsInfini
	 */
	public static double getMoinsInfini() {
		return MOINS_INFINI;
	}

  /* (non-Javadoc)
	 * @see java.lang.Object#toString()
	 */
	@Override
	public String toString() {
		String st = new String() ;
		st = st + "[[nbrBatch="+nbrBatch+", " + "evaluation="+evaluation+", evaluationCustomer=" + evaluationCustomer				
				+ ", evaluationTransporter=" + evaluationTransporter  ;
		st = st + "\n  bi=[" ;
		for (int i=0;i<supplyLinkProblem.getN();i++) {
			st = st + processingSchedule[i].getBatchNumber() ;
			if (i<supplyLinkProblem.getN()-1) st = st + ", "; else st = st + "]" ;
		}
		st = st + "\n  Ci=[" ;
		for (int i=0;i<supplyLinkProblem.getN();i++) {
			st = st + processingSchedule[i].getDeliveryCompletionTime() ;
			if (i<supplyLinkProblem.getN()-1) st = st + ", "; else st = st + "]" ;
		}
		st = st + "]" ;
		
		return st;
	}

	@Override
	public GSupplyLinkSolution clone() {
		return new GSupplyLinkSolution(supplyLinkProblem, processingSchedule,
				nbrBatch, makespanForProduction, makespanForTransportation,
				solValueOfTransportationProblem, evaluation,
				evaluationTransporter, evaluationCustomer,
				dateTransporterDeparture, dateProductionDeparture);
	}

	public void setBatchIndice(int j, int bi) {
		processingSchedule[j].setBatchIndice(bi);
	}

	public void setCompletionTimes(int j, double c) {
		processingSchedule[j].setDeliveryCompletionTime(c);
	}

	public int open(String filename) {
		if (filename == null)
			return 1;

		FichierEntree fe = new FichierEntree(filename);

		int encore = 1;
		while (encore == 1) {

			String s = fe.lireLigne();
			if (s == null) {
				break;
			}

			StringTokenizer st = new StringTokenizer(s, new String(":="));
			String sg = st.nextToken().trim();

			if (sg.compareToIgnoreCase("NBR_BATCH") == 0)
				setNbrBatch(Integer.parseInt(st.nextToken().trim()));

			if (sg.compareToIgnoreCase("BATCH_INDICES") == 0) {
				StringTokenizer st2 = new StringTokenizer(st.nextToken().trim(), new String(";"));
				for (int j = 0; j < supplyLinkProblem.getN(); j++) {
					setBatchIndice(j, Integer.parseInt(st2.nextToken().trim()));
				}
			}

			if (sg.compareToIgnoreCase("COMPLETION_TIMES") == 0) {
				StringTokenizer st2 = new StringTokenizer(st.nextToken().trim(), new String(";"));
				for (int j = 0; j < supplyLinkProblem.getN(); j++) {
					setCompletionTimes(j, (new Double(st2.nextToken())).doubleValue() );
				}
			}

			if (sg.compareToIgnoreCase("EOF") == 0) {
				encore = 0;
			}

		}

		fe.fermer();

		return 0;

	}

	public double evaluate() {
		evaluationTransporter = nbrBatch * supplyLinkProblem.getTransporter(0).getDeliveryCost() ;
		evaluationCustomer = 0 ;
		for (int i=0;i<supplyLinkProblem.getN();++i) {
			double jobcustcost = supplyLinkProblem.getJobData()[i].getHoldingCost() ;
			double jobduedate = supplyLinkProblem.getJobData()[i].getDueDate() ;
			double jobcomptime =  processingSchedule[i].getDeliveryCompletionTime() ;
			evaluationCustomer += jobcustcost*(jobduedate-jobcomptime) ;
		}
		evaluation = evaluationTransporter + evaluationCustomer ;
		return evaluation;
	}

}
